//
// Created by yyancy on 2019/11/17.
//
#include <iostream>

using namespace std;

template<typename T, typename A=allocator<T>>
class vector {
    A alloc;
    int sz;
    T *elem;
    int space;
public:
    vector() : sz{0}, elem{nullptr}, space{0} {}

    explicit vector(int s)
            : sz{s}, elem{new T[sz]} {
        for (int i = 0; i < sz; ++i) elem[i] = 0;

    }

    ~vector() {
        cout << "delete elem.." << endl;
        delete[]elem;
    }

    vector(initializer_list<double> lst)
            : sz{static_cast<int>(lst.size())}, elem{new double[sz]} {
        copy(lst.begin(), lst.end(), elem);
    }

    vector(const vector &);

    vector(vector &&);

    vector &operator=(const vector &);

    vector &operator=(vector &&);

    void reserve(int newalloc);

    T &at(int n);

    const T &at(int n) const;

    double &operator[](int n) {
        return elem[n];
    }

    double operator[](int n) const {
        return elem[n];
    }

    int size() const {
        return sz;
    }

    double get(int i) const {
        return elem[i];
    }

    int capacity() const {
        return space;
    }

    void resize(int newsize, T def = T());

    void push_back(T d);

};

template<typename T, typename A>
const T &vector<T, A>::at(int n) const {
    if (n < 0 || sz <= n)throw out_of_range("index");
    return elem[n];
}

template<typename T, typename A>
T &vector<T, A>::at(int n) {
    if (n < 0 || sz <= n)throw out_of_range("index");
    return elem[n];
}

template<typename T, typename A>
void vector<T, A>::reserve(int newalloc) {
    if (newalloc <= space)return;
    T *p = alloc.allocate(newalloc);
    for (int i = 0; i < sz; ++i) {
        alloc.construct(&p[i], elem[i]);
    }
    for (int j = 0; j < sz; ++j) {
        alloc.destroy(&elem[j]);
    }
    alloc.deallocate(elem, space);
    elem = p;
    space = newalloc;
}

template<typename T, typename A>
void vector<T, A>::push_back(T d) {
    if (space == 0)
        reserve(8);
    else if (sz == space)
        reserve(2 * space);
    alloc.construct(&elem[sz], d);
    ++sz;
}

template<typename T, typename A>
void vector<T, A>::resize(int newsize, T def) {
    reserve(newsize);
    for (int i = sz; i < newsize; ++i) {
        alloc.construct(&elem[i]);
    }
    for (int j = newsize; j < sz; ++j) {
        alloc.destroy(&elem[j]);
    }
    sz = newsize;
}

/**
 * 拷贝构造函数
 * @param args
 */
template<typename T, typename A>
vector<T, A>::vector(const vector &args)
        : sz{args.sz}, elem{new double[sz]} {
    copy(args.elem, args.elem + sz, elem);
}

/**
 * 拷贝赋值函数
 * @return
 */
template<typename T, typename A>
vector<T, A> &vector<T, A>::operator=(const vector &a) {

    if (this == &a) // 自赋值
        return *this;

    if (a.sz <= space) { // 空间足够的情况下
        for (int i = 0; i < a.sz; ++i) {
            elem[i] = a.elem[i];
        }
        sz = a.sz;
        return *this;
    }

    auto *p = new double[a.sz];
    copy(a.elem, a.elem + a.sz, p);
    delete[] elem;
    space = sz = a.sz;
    elem = p;
    return *this;
}

template<typename T, typename A>
vector<T, A>::vector(vector &&a)
        : sz{a.sz}, elem{a.elem} {
    a.sz = 0;
    a.elem = nullptr;
}

/**
 * 移动赋值
 * @param a
 * @return
 */
template<typename T, typename A>
vector<T, A> &vector<T, A>::operator=(vector &&a) {
    delete[] elem;
    elem = a.elem;
    sz = a.sz;
    a.elem = nullptr;
    a.sz = 0;
    return *this;
}


void f3(int n) {
    double *p = new double[n];
    vector<double> v(n);
    delete[] p;
}

int main() {
    vector<double> v{1, 2, 3};
    vector<double> v2 = v;

    for (int i = 0; i < v2.size(); ++i) {
        cout << v2.get(i) << '\t';
    }

    vector<double> v3 = {3};
    v3[1] = 2;
    cout << v3[1];
//    cout << 23232 << endl;
//    f3(3);
}